package org.apache.commons.graph.algorithms.shortestpath.internal

import org.apache.commons.graph.weight.OrderedMonoid

/**
 * Stores and compares Graph Vertices weights.
 *
 * @param <V> the Graph vertices type
 * @param <W> the weight type
</W></V> */
internal class ShortestDistances<V, W>(
    private val weightOperations: OrderedMonoid<W>
) : Comparator<V> {
    private val distances: MutableMap<V, W> = HashMap()

    /**
     * Checks if the input `Vertex` was already visited.
     *
     * @param vertex the input `Vertex`
     * @return true if the input `Vertex` was already visited, false otherwise.
     */
    fun alreadyVisited(vertex: V): Boolean {
        return distances.containsKey(vertex)
    }

    /**
     * {@inheritDoc}
     */
    override fun compare(left: V, right: V): Int {
        if (!alreadyVisited(left) && !alreadyVisited(right)) {
            return 0
        } else if (!alreadyVisited(left)) {
            return 1
        } else if (!alreadyVisited(right)) {
            return -1
        }
        return weightOperations.compare(getWeight(left), getWeight(right))
    }

    /**
     * Returns the distance related to input vertex, or null if it wasn't previously visited.
     *
     * **NOTE**: the method [alreadyVisited] should be used first to check if
     * the input vertex was already visited and a distance value is available for it.
     *
     * @param vertex the vertex whose distance has to be retrieved
     * @return the distance related to input vertex, or null if it wasn't previously visited.
     */
    fun getWeight(vertex: V): W? {
        return distances[vertex]
    }

    /**
     * Update the input vertex distance.
     *
     * @param vertex the vertex for which the distance has to be updated
     * @param distance the new input vertex distance
     */
    fun setWeight(vertex: V, distance: W) {
        distances[vertex] = distance
    }
}